#include <stdio.h>
#include <string.h>
#include <assert.h>
//函数一定要保持高度的耦合性，即专一性要强，不要封装过多的功能。

//a.长度不受限制的字符串库函数
//1.strlen()三种模拟实现的方式
////原版：
//int main()
//{
//    char arr[] = "abcdef";
//    int len = strlen(arr);
//    printf("%d\n",len);
//    return 0;
//}
////①逐步计时
//int my_strlen(const char* arr)
//{
//    assert(arr);
//    int sum = 0;
//    while(*arr++ != '\0')
//    {
//        sum += 1;
//    }
//    return sum;
//}
//int main()
//{
//    char arr[] = "abcde";
//    int len = my_strlen(arr);
//    printf("%d\n",len);
//}
////②递归
//int my_strlen(const char* arr,int sum)
//{
//    assert(arr);
//    while(*arr != '\0')
//    {
//        sum = 1;//sum是不用改变的，每次返回的值都要是1，只是要记录arr(首元素地址)变了几次，所以才需要改变arr(首元素地址)。
//        return sum + my_strlen(arr+1,sum);
//    }
//}
//int main()
//{
//    char arr[] = "abcdefg";
//    int sum = 0;
//    int len = my_strlen(arr,sum);
//    printf("%d\n",len);
//    return 0;
//}
////③指针-指针
////找到'\0',减去首元素地址，就是元素的个数。
//int my_strlen(const char * arr)
//{
//    assert(arr);
//    char* temp = arr;
//    while(*arr != '\0')
//    {
//        arr++;
//    }
//    return arr-temp;
//}
//int main()
//{
//    char arr[] = "abcde";
//    int len = my_strlen(arr);
//    printf("%d\n",len);
//    return 0;
//}

////2.strcpy()    复制
////char* strcpy(char* dest,const char* source);
////把source放到dest这里，源后
////①源字符串必须以'\0'结束。
////②会将源字符串的'\0'拷贝到目标空间,而后，因为打印只打印出到'\0'的字符串，所以dest显示在屏幕面前的只有源字符串。
////（dest中途被源字符串的'\0'“切断了”）
////③dest要足够大，确保能够放sour.
////④dest空间必须可变。
//char* my_strcpy(char* dest,const char* sour)
//{
//    assert(sour && dest);
//    char* temp = dest;
//    while(*sour != '\0')
//    {
//        *dest++ = *sour++;
//    }
//    *dest = '\0';
//    return temp;
//}
//int main() {
//    char sour[] = "abcdef";
//    char dest[20] = "xxxxxxxxxxxx";
//    printf("%s\n",dest);
////    //库函数
////    strcpy(dest, sour);
////    printf("%s\n",dest);
//    char* simu = my_strcpy(dest,sour);
//    printf("%s\n",simu);
//    return 0;
//}

////3.strcat()   追加
////char* strcat(char* dest,const char* source);
////把dest中的'\0'覆盖掉（换成source的第一个字符），加上source。
////①源字符串必须以'\0'结束。
////②dest should 足够大，能够容纳source的内容。
////③目标空间必须可修改。
////④不可自己给自己追加。
//char* my_strcat(char* dest,const char* source)
//{
//    assert(dest && source);
//    char* temp = dest;
//    //找到dest的'\0',然后把sourece整个追加上去。
//    while(*dest != '\0')
//    {
//        dest++;
//    }
//    while(*source != '\0')
//    {
//        *dest++ = *source++;
//    }
//    *(dest+1) = '\0';
//    return temp;
//}
//int main()
//{
//    char source[] = "abcdef";
//    char dest[20] = "xxxxxxx";
////    //原版
////    char* temp = strcat(dest,source);
////    printf("%s\n",temp);
//    //模拟实现
//    char* temp1 = my_strcat(dest,source);
//    printf("%s\n",temp1);
//    return 0;
//}

////4.strcmp()     比较    前跟后
////int strcmp(const char* str1,const char* str2);前跟后比
////是比较每个字符的Ascall码值，不是比较字符串长度。
////①if(str1 > str2):return >0 的数字；
////②if(str1 = str2):return 0;
////③if(str1 < str2):return <0 的数字；
//int my_strcmp(const char* arr,const char* arr1)
//{
//    assert(arr && arr1);
//    //先拿第一个进行比较，以此类推，直到找到不同的字符为止。
//    while(*arr == *arr1 && (*arr != '\0') && (*arr1 != '\0'))
//    {
//        arr++;
//        arr1++;
//    }
//    //已经找到不同的了，这时候就要比较一下了。因为字符本质上是整型，所以可直接比较。
//    if(*arr > *arr1)
//        return 1;
//    else if(*arr == *arr1)
//        return 0;
//    else
//        return -1;
//}
//int main()
//{
//    char arr[] = "abcde";
//    char arr1[] = "abcde";
////    //原版
////    if(strcmp(arr,arr1) > 0)
////        printf("arr > arr1");
////    else if(strcmp(arr,arr1) == 0)
////        printf("arr = arr1");
////    else
////        printf("arr < arrr1");
//    //模拟版
//    int temp = my_strcmp(arr,arr1);
//    if(temp > 0)
//        printf("arr > arr1");
//    else if(temp == 0)
//        printf("arr = arr1");
//    else
//        printf("arr < arr1");
//    return 0;
//}


//b.长度受限制字符串函数
////5.strncpy()
////char* strncpy(char* dest,const char* source,size_t num);
////工作原理：①if sour 符合输入的字节要求，直接拷贝覆盖过去；
////②if source 不符合输入的字节要求，（即源字符串长度（包括'\0'）< 要求的字节数）把源字符串的'\0'拷贝过去后，后面自动补'\0'.
////将源字符串的前number个字符复制到dest。
////①dest应该足够大。
////②从目的地的首地址开始覆盖。
//char* my_strncpy(char* destna,const char* source,size_t num)
//{
//    //不要从外面传进来长度，要严格按照它的要求
//    assert(destna && source);
//    char* temp = destna;
//    char* temp1 = source;//虽然有失偏颇，但是确实只能这样的，求长度势必会改变指针位置
//    int i = 0;
//    int g = 0;
//    //应该先测一下source长度
//    while(*source++ != '\0')
//    {
//        i++;
//    }
//    if(num <= i+1)
//    {
//        for(g = 0;g < num;g++)
//        {
//            *destna++ = *temp1++;
//        }
//        return temp;
//    }
//    else
//    {
//        for(g = 0;g < i;g++)//先到达i
//        {
//            *destna++ = *temp1++;
//        }
//        for(g = 0;g < num-i;g++)
//        {
//            *destna = '\0';
//            destna++;
//        }
//        return temp;
//    }
//}
//int main()
//{
//    char source[] = "abcde";
//    char destna[20] = "gkhjxxxxxx";
////    //原版
////    strncpy(destna,source,5);
////    printf("%s\n",destna);
////    strncpy(destna,source,9);
////    printf("%s\n",destna);
//////    strncpy(destna,source,6);
//////    printf("%s\n",destna);
//    //模拟
//    char* temp = my_strncpy(destna,source,5);
//    printf("%s\n",temp);
//    return 0;
//}

////6.strncat()     指定个数在destina后面追加
////char* strncat (char* destina,const char* source,size_t num)
////工作原理：①if 源字符串长度符合输入的字节数要求，直接把dest的'\0'覆盖过去，开始追加。追加完之后自动补一个'\0'，
////因为追加后仍然是字符串，字符串以'\0'结尾。
////②if 长度不符合输入的字节数要求，（即源字符串长度（包括'\0'）< 要求的字节数）把destina的'\0'覆盖过去后，
////开始追加（source的个数-1），until source的'\0'，结束。
////③destina要足够大
//char* my_strncat(char* destina,const char* source,size_t num)
//{
//    assert(destina &&source);
//    //首先找到destina的'\0'位置，然后把source接上去
//    char* temp = destina;
//    char* temp1 = source;
//    unsigned int i = 0;
//    while(*destina != '\0')
//    {
//        destina++;
//    }
//    while(*source != '\0')
//    {
//        source++;
//        i++;
//    }
//    if(i+1 > num)
//    {
//        for(i = 0;i < num;i++)
//        {
//            *destina++ = *temp1++;
//        }
//        *destina = '\0';
//        return temp;
//    }
//    else
//    {
//        unsigned int g = 0;
//        for(g = 0;g < i;g++)
//        {
//            *destina++ = *temp1++;
//        }
//        *destina = '\0';
//        return temp;
//    }
//}
//int main()
//{
//    char source[] = "abcdef";
//    char destina[20] = "xxxxxxxx";
////    printf("%s\n",strncat(destina,source,8));
//    int i = 3;
//    char* temp = my_strncat(destina,source,i);
//    printf("%s\n",temp);
//    return 0;
//}

//7.strncmp()    按字节数要求比较str1 跟 str2.
//int strncmp(const char* str1,const char* str2,size_t num)
//①if 第一个不匹配的字符在str1中的值低于str2中的值，return < 0;
//②if 两个字符串相等 return 0;
//③if 第一个不匹配的字符在str1中的值大于在str2中的值，return > 0;
//一样的，还是比较Ascll 码值而不是长度。
int my_strncmp(const char* str1,const char* str2,size_t num)
{
    int i = 0;
    for(i = 0;i < num;i++)
    {
        //比较两者，一直到找出不同的两个
        if(*str1 != *str2)
            break;
        else
        {
            if(i != num-1)
            {
                str1++;
                str2++;
            }
        }
    }
    //前大于后
    if(*str1 > *str2)
        return 1;
    else if(i == num)
        return 0;
    else
        return -1;
}
int main()
{
    char str1[] = "abcae";
    char str2[] = "cbccd";
//    int temp = strncmp(str1,str2,4);
//    printf("%d\n",temp);
    int temp = my_strncmp(str1,str2,4);
    printf("%d\n",temp);
}